﻿namespace PowerSong.Import
    {
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.IO.Compression;
    using System.Xml;
    using PowerSong.SongDatabase;
    using PowerSong.SongDatabase.Legacy;
    using PowerSong.SongDatabase.Legacy.Items;

    public class LegacyExportFileImport : BaseImport
        {

        private string fileName = null;

        public LegacyExportFileImport(PowerSong.SongDatabase.Database destinationDatabase, string legacyExportFileName)
            : base(destinationDatabase)
            {
            this.fileName = legacyExportFileName;
            }

        protected override void Import(Category category, List<string> messages)
            {

            // Decompress all of the data in the given file into a memory stream
            using (var fileStream = new FileStream(fileName, FileMode.Open))
                {
                using (var zipStream = new GZipStream(fileStream, CompressionMode.Decompress))
                    {
                    using (var memoryStream = new MemoryStream())
                        {
                        var buffer = new byte[4096];
                        int bytesRead = zipStream.Read(buffer, 0, 4096);
                        while (bytesRead > 0)
                            {
                            memoryStream.Write(buffer, 0, bytesRead);
                            bytesRead = zipStream.Read(buffer, 0, 4096);
                            }

                        // Start reading from the beginning of the memory stream
                        memoryStream.Position = 0;
                        using (var file = new BinaryReader(memoryStream))
                            {
                            ProcessArchive(file, category, messages);
                            }
                        }
                    }
                }

            }

        private void ProcessArchive(BinaryReader file, Category category, List<string> messages)
            {

            // Read each file in the stream
            var overwriteItems = true;
            while (file.BaseStream.Position < file.BaseStream.Length)
                {
                var nextFileName = file.ReadString();
                var fileLength = file.ReadInt32();
                var fileContents = file.ReadBytes(fileLength);

                // Work with the current file in the stream
                switch (Path.GetExtension(nextFileName).ToUpper())
                    {

                    case ".SONG":
                        var songID = new Guid(Path.GetFileNameWithoutExtension(nextFileName));
                        ImportSong(category, songID, fileContents, overwriteItems, messages);
                        break;

                    case ".XML":

                        if (nextFileName.ToUpper() == "STYLES.XML")
                            {
                            ImportStyles(fileContents, overwriteItems, messages);
                            }
                        else if (nextFileName.ToUpper() == "SONGCATEGORIES.XML")
                            {
                            messages.Add("Song Categories have been included in the selected file but they cannot be imported.");
                            }
                        else
                            {
                            messages.Add("Skipped over unknown file: '" + nextFileName + "'.");
                            }
                        break;

                    case ".PLUGIN":
                        messages.Add("Did not import plugin '" + nextFileName + "' because plugins are no longer supported in this version of PowerSong.");
                        break;

                    default:
                        messages.Add("Skipped over unknown file: '" + nextFileName + "'.");
                        break;

                    }

                }

            }

        private void ImportSong(Category category, Guid identifier, byte[] fileContents, bool overwriteExisting, List<string> messages)
            {

            // Determine whether or not to import or overwrite the song
            var importThisSong = true;
            if (Destination.Songs.Contains(identifier))
                {
                if (!overwriteExisting)
                    {
                    messages.Add("The song '" + identifier.ToString() + "' already exists.");
                    importThisSong = false;
                    }
                }

            if (importThisSong == true)
                {

                try
                    {

                    // Add to the database
                    var oldSong = SongItem.Load(fileContents, identifier);
                    var newSong = LegacyConverter.ConvertSong(oldSong);
                    newSong.Categories.Add(category);
                    Destination.Songs.Write(newSong);

                    }
                catch (Exception ex)
                    {
                    messages.Add("Error importing song: " + ex.Message);
                    }

                }

            }

        private void ImportStyles(byte[] fileContents, bool overwriteExisting, List<string> messages)
            {

            try
                {

                // Read the styles into a legacy PowerSong dataset
                var styleData = new Data();
                using (var reader = new XmlTextReader(new MemoryStream(fileContents)))
                    {
                    styleData.ReadXml(reader);
                    }

                // Import each of the styles
                foreach (Data.StylesRow row in styleData.Styles)
                    {
                    try
                        {
                        var styleExists = Destination.Styles.Contains(row.StyleID);
                        if (!styleExists || overwriteExisting)
                            {

                            // Add the new style
                            var newStyle = LegacyConverter.ConvertStyle(styleData, row);
                            Destination.Styles.Write(newStyle);

                            // Add an appropriate message
                            if (styleExists)
                                {
                                messages.Add("Replaced style '" + row.Name + "'.");
                                }

                            }
                        else
                            {
                            messages.Add("The style '" + row.Name + "' already exists, therefore it has been ignored.");
                            }

                        }
                    catch (Exception)
                        {
                        messages.Add("Cannot import style '" + row.Name + "' because it is incompatible.");
                        }

                    }

                }
            catch (Exception)
                {
                messages.Add("The styles file contained in the archive is invalid.");
                }

            }

        }

    }
